﻿Imports ESRI.ArcGIS.Carto
Imports ESRI.ArcGIS.Display

Public Class ParseLabel
    ''' <summary>
    ''' 是否将字段名称更改为小写，适配postgis，postgis字段名称全为小写
    ''' </summary>
    Private mFieldNameLower As Boolean = True
    Private mSetLabelScale As Boolean = True
    Private geometryFieldName As String = ""
    Private _initGeometryFieldName As String = ""
    Sub New(fieldnamLower As Boolean, setLabelScale As Boolean, shapeFieldName As String)
        mFieldNameLower = fieldnamLower
        mSetLabelScale = setLabelScale
        geometryFieldName = shapeFieldName
        _initGeometryFieldName = shapeFieldName
    End Sub
    ''' <summary>
    ''' 解析图层注记，存放在style中
    ''' </summary>
    ''' <param name="style"></param>
    ''' <param name="ftrLyr"></param>
    Public Sub ParseLabel(style As SLDStyle, ftrLyr As IFeatureLayer)
        If ftrLyr Is Nothing Then
            Return
        End If
        Dim pGeoLyr As IGeoFeatureLayer = ftrLyr
        If Not pGeoLyr.DisplayAnnotation Then
            Return
        End If
        '##################################################
        Dim pDataLayer As IDataLayer = ftrLyr
        Dim pFtrclsName As ESRI.ArcGIS.Geodatabase.IFeatureClassName = pDataLayer.DataSourceName
        Dim ftrclsType As ESRI.ArcGIS.Geometry.esriGeometryType = pFtrclsName.ShapeType
        If ftrclsType = ESRI.ArcGIS.Geometry.esriGeometryType.esriGeometryPoint Then
            geometryFieldName = ""
        Else
            geometryFieldName = _initGeometryFieldName
        End If
        ' #################################
        Dim annoPropsColl As IAnnotateLayerPropertiesCollection
        annoPropsColl = pGeoLyr.AnnotationProperties
        If annoPropsColl.Count = 0 Then
            Return
        End If
        Dim minscale As Double = ftrLyr.MinimumScale
        Dim maxscale As Double = ftrLyr.MaximumScale
        Dim annoLayerProps As IAnnotateLayerProperties = Nothing
        For i As Integer = 0 To annoPropsColl.Count - 1
            annoPropsColl.QueryItem(i, annoLayerProps)
            If Not annoLayerProps.DisplayAnnotation Then
                Continue For
            End If
            Dim rule As New SLDRule()
            rule.ruleName = annoLayerProps.Class
            rule.description = "Label"
            rule.symbolType = SLDStyle.SymbolizerType.TextSymbolizer
            rule.sql = annoLayerProps.WhereClause
            If mSetLabelScale Then
                Dim annoMinScale As Double = annoLayerProps.AnnotationMinimumScale
                Dim annoMaxScale As Double = annoLayerProps.AnnotationMaximumScale
                If annoMinScale < 0.001 Then
                    annoMinScale = minscale
                End If
                If annoMaxScale < 0.001 Then
                    annoMaxScale = maxscale
                End If
                setScaleOfRule(rule, annoMinScale, annoMaxScale)
            End If
            Dim symbolizer As New SLDSymbolizer
            Dim fields As ESRI.ArcGIS.Geodatabase.IFields = Nothing
            If ftrLyr.FeatureClass IsNot Nothing Then
                fields = ftrLyr.FeatureClass.Fields
            End If
            ParseAnnotateLayerProperties(symbolizer, annoLayerProps, fields)
            rule.add(symbolizer)
            '设置rule的参数
            setSldGenralVendorOption(rule)
            style.rules.Add(rule)
        Next
    End Sub
    ''' <summary>
    ''' 设置最大最小比例
    ''' </summary>
    ''' <param name="rule"></param>
    ''' <param name="minscale"></param>
    ''' <param name="maxscale"></param>
    Private Sub setScaleOfRule(rule As SLDRule, minscale As Double, maxscale As Double)
        If minscale > 0.001 Then
            rule.add(New SLdParameter("MaxScaleDenominator", minscale, True))
        End If
        If maxscale > 0.001 Then
            rule.add(New SLdParameter("MinScaleDenominator", maxscale, True))
        End If
    End Sub
    ''' <summary>
    ''' 解析注记属性
    ''' </summary>
    ''' <param name="symbolizer"></param>
    ''' <param name="annoLayerProps"></param>
    Private Sub ParseAnnotateLayerProperties(symbolizer As SLDSymbolizer,
                                            annoLayerProps As IAnnotateLayerProperties,
                                            fields As ESRI.ArcGIS.Geodatabase.IFields)
        If Not TypeOf annoLayerProps Is ILabelEngineLayerProperties Then
            Return
        End If
        Dim pLabelEngineLayerProps As ILabelEngineLayerProperties = annoLayerProps
        Dim txtSym As ITextSymbol = pLabelEngineLayerProps.Symbol
        Dim fillSldSymbol As SLDSymbol = getSldFillSymbol(txtSym)
        If fillSldSymbol Is Nothing Then
            Return
        End If
        Dim labelSymbol As SLDSymbol = getSldLabelExpressionSymbol(pLabelEngineLayerProps.Expression, fields)
        Dim fontSldSymbol As SLDSymbol = getSldFontSymbol(txtSym)
        Dim labelPlaceSldSymbol As SLDSymbol = getSldLabelPlacementSymbol(pLabelEngineLayerProps)
        Dim haloSldSymbol As SLDSymbol = getSldHaloSymbol(txtSym)

        Dim sldLyr As New SLDSymbolLayer()
        '添加几何
        If (Not String.IsNullOrWhiteSpace(geometryFieldName)) Then
            Dim geomSymbol As New SLDSymbol("Geometry")
            Dim funcSymbol As New SLDSymbol("Function", True, name_value:="interiorPoint")
            funcSymbol.sldParamOrSymbols.Add(New SLdParameter("PropertyName", geometryFieldName, True, "", True))
            geomSymbol.sldParamOrSymbols.Add(funcSymbol)
            sldLyr.SymbolsOrParas.Add(geomSymbol)
        End If
        '###################
        sldLyr.SymbolsOrParas.Add(labelSymbol)
        If fontSldSymbol IsNot Nothing Then
            sldLyr.SymbolsOrParas.Add(fontSldSymbol)
        End If
        If labelPlaceSldSymbol IsNot Nothing Then
            sldLyr.SymbolsOrParas.Add(labelPlaceSldSymbol)
        End If
        If haloSldSymbol IsNot Nothing Then
            sldLyr.SymbolsOrParas.Add(haloSldSymbol)
        End If
        sldLyr.SymbolsOrParas.Add(fillSldSymbol)
        setSldFontVendorOption(sldLyr, txtSym)
        setSldWeightAndSoOnVendorOption(sldLyr, pLabelEngineLayerProps)
        symbolizer.addLayer(sldLyr)
    End Sub
    ''' <summary>
    ''' Fill
    ''' </summary>
    ''' <param name="txtSymbol"></param>
    ''' <returns></returns>
    Private Function getSldFillSymbol(txtSymbol As ITextSymbol) As SLDSymbol
        Dim sldColor As String = getStringForColor(txtSymbol.Color)
        If String.IsNullOrWhiteSpace(sldColor) Then
            Return Nothing
        End If
        Dim fillSldSym As New SLDSymbol("Fill")
        fillSldSym.sldParamOrSymbols.Add(New SLdParameter("fill", sldColor))
        Return fillSldSym
    End Function
    ''' <summary>
    ''' Halo
    ''' </summary>
    ''' <param name="txtSymbol"></param>
    ''' <returns></returns>
    Private Function getSldHaloSymbol(txtSymbol As ITextSymbol) As SLDSymbol
        Dim pMask As IMask = txtSymbol
        If pMask.MaskStyle = esriMaskStyle.esriMSNone Then
            Return Nothing
        End If
        Dim size As Double = pMask.MaskSize
        If size < 0.0001 Then
            Return Nothing
        End If
        Dim sldColor As String = getStringForColor(pMask.MaskSymbol.Color)
        If String.IsNullOrWhiteSpace(sldColor) Then
            Return Nothing
        End If
        Dim haloSldSym As New SLDSymbol("Halo")
        If size > 0 Then
            haloSldSym.sldParamOrSymbols.Add(New SLdParameter("Radius", size, True))
        End If
        If Not String.IsNullOrWhiteSpace(sldColor) Then
            Dim fillSldSYm As New SLDSymbol("Fill")
            fillSldSYm.sldParamOrSymbols.Add(New SLdParameter("fill", sldColor))
            haloSldSym.sldParamOrSymbols.Add(fillSldSYm)
        End If
        Return haloSldSym
    End Function

#Region "#########获取标注注记条件sql，只解析多字段和字符连接,需扩展splitExpression函数........"
    ''' <summary>
    ''' 注记sql语句
    ''' </summary>
    ''' <param name="labelExpression"></param>
    ''' <returns></returns>
    Private Function getSldLabelExpressionSymbol(labelExpression As String, fields As ESRI.ArcGIS.Geodatabase.IFields) As SLDSymbol
        Dim labelSymbol As New SLDSymbol("Label")
        Dim expressions As List(Of Object) = splitExpression(labelExpression, fields)
        labelSymbol.sldParamOrSymbols.AddRange(expressions)
        Return labelSymbol
    End Function
    ''' <summary>
    ''' 将sql语句拆分
    ''' </summary>
    ''' <param name="expression">sql语句</param>
    ''' <returns>才分后的参数</returns>
    Private Function splitExpression(expression As String, fields As ESRI.ArcGIS.Geodatabase.IFields) As List(Of Object)
        Dim eSPlit() As String = expression.Split("+&".ToCharArray, StringSplitOptions.RemoveEmptyEntries)
        Dim paras As New List(Of Object)
        Dim lastProperty As Boolean = False
        For Each e In eSPlit
            e = e.Replace(" ", "")
            Dim eLower As String = e.ToLower.Replace(" ", "")
            If e.StartsWith("[") AndAlso e.EndsWith("]") Then
                Dim fld As String = e.Replace("[", "").Replace("]", "")
                If mFieldNameLower Then
                    fld = fld.ToLower.Trim
                End If
                If lastProperty Then
                    Dim para As New SLdParameter("", "")
                    para.mCdata = True
                    paras.Add(para)
                End If
                '数字格式化
                Dim isNumberFormated As Boolean = False
                If fields IsNot Nothing AndAlso fields.FindField(fld) >= 0 Then
                    Dim field As ESRI.ArcGIS.Geodatabase.IField = fields.Field(fields.FindField(fld))
                    If field.Type = ESRI.ArcGIS.Geodatabase.esriFieldType.esriFieldTypeDouble Then
                        isNumberFormated = True
                        Dim funcSym As New SLDSymbol("Function", True, "numberFormat")
                        funcSym.sldParamOrSymbols.Add(New SLdParameter("Literal", "0.###", True, ogcPrefix:=True))
                        funcSym.sldParamOrSymbols.Add(New SLdParameter("PropertyName", fld, True, ogcPrefix:=True))
                        paras.Add(funcSym)
                    End If
                End If
                '
                If Not isNumberFormated Then
                    paras.Add(New SLdParameter("PropertyName", fld, True, ogcPrefix:=True))
                End If
                lastProperty = True
            Else
                lastProperty = False
                If eLower = "vbnewline" OrElse eLower = "chr(13)" Then
                    '回车
                    Dim para As New SLdParameter("", vbNewLine)
                    para.mCdata = True
                    paras.Add(para)
                Else
                    e = e.Replace("""", "")
                    Dim para As New SLdParameter("", e)
                    para.mCdata = True
                    paras.Add(para)
                End If
            End If
        Next
        Return paras
    End Function
#End Region

#Region "设置注记字体"
    ''' <summary>
    ''' 设置字体
    ''' </summary>
    ''' <param name="txtSymbol"></param>
    ''' <returns></returns>
    Private Function getSldFontSymbol(txtSymbol As ITextSymbol) As SLDSymbol
        Dim font As stdole.IFontDisp = txtSymbol.Font
        Dim fontSldSymbol As New SLDSymbol("Font")
        fontSldSymbol.sldParamOrSymbols.Add(New SLdParameter("font-family", font.Name))
        fontSldSymbol.sldParamOrSymbols.Add(New SLdParameter("font-size", font.Size))
        If (font.Italic) Then
            fontSldSymbol.sldParamOrSymbols.Add(New SLdParameter("font-style", "italic"))
        End If
        If font.Bold Then
            fontSldSymbol.sldParamOrSymbols.Add(New SLdParameter("font-weight", "bold"))
        End If
        Return fontSldSymbol
    End Function
    ''' <summary>
    ''' 设置字体
    ''' </summary>
    ''' <param name="labelSldLayer"></param>
    ''' <param name="txtSymbol"></param>
    Private Sub setSldFontVendorOption(labelSldLayer As SLDSymbolLayer,
                                       txtSymbol As ITextSymbol)
        Dim font As stdole.IFontDisp = txtSymbol.Font
        If font.Underline Then
            labelSldLayer.SymbolsOrParas.Add(New SLdParameter("underlineText", "true", False, "VendorOption"))
        End If
        If font.Strikethrough Then
            labelSldLayer.SymbolsOrParas.Add(New SLdParameter("strikethroughText", "true", False, "VendorOption"))
        End If
        If txtSymbol.RightToLeft Then
            labelSldLayer.SymbolsOrParas.Add(New SLdParameter("forceLeftToRight", "false", False, "VendorOption"))
        End If
        Dim pFormatSym As IFormattedTextSymbol = txtSymbol
        If Math.Abs(pFormatSym.CharacterSpacing - 1) > 0.00001 Then
            labelSldLayer.SymbolsOrParas.Add(New SLdParameter("charSpacing", pFormatSym.CharacterSpacing, False, "VendorOption"))
        End If
        labelSldLayer.SymbolsOrParas.Add(New SLdParameter("wordSpacing", pFormatSym.WordSpacing, False, "VendorOption"))
    End Sub
#End Region

#Region "设置注记位置"
    Private Function getSldLabelPlacementSymbol(pLabelEngineLayerProps As ILabelEngineLayerProperties) As SLDSymbol
        Dim ptSldSym As SLDSymbol = getSldPointLabelPlaceMentSymbol(pLabelEngineLayerProps.Symbol)
        Dim lineSldSym As SLDSymbol = getSldLineLabelPlacementSymbol(pLabelEngineLayerProps)
        If ptSldSym Is Nothing AndAlso lineSldSym Is Nothing Then
            Return Nothing
        End If
        Dim lSldSym As New SLDSymbol("LabelPlacement")
        If ptSldSym IsNot Nothing Then
            lSldSym.sldParamOrSymbols.Add(ptSldSym)
        End If
        If lineSldSym IsNot Nothing Then
            lSldSym.sldParamOrSymbols.Add(lineSldSym)
        End If
        Return lSldSym
    End Function
    ''' <summary>
    ''' 设置点位置放置
    ''' </summary>
    ''' <param name="txtSym"></param>
    ''' <returns></returns>
    Private Function getSldPointLabelPlaceMentSymbol(txtSym As ITextSymbol) As SLDSymbol
        Dim placeSldSym As New SLDSymbol("PointPlacement")
        Dim anchorSldSym As SLDSymbol = getSldAnchorSymbol(txtSym)
        If anchorSldSym IsNot Nothing Then
            placeSldSym.sldParamOrSymbols.Add(anchorSldSym)
        End If
        Dim displaceMent As SLDSymbol = getSldDisplamentSymbol(txtSym)
        If displaceMent IsNot Nothing Then
            placeSldSym.sldParamOrSymbols.Add(displaceMent)
        End If
        If (Math.Abs(txtSym.Angle) > 0.0001) Then
            placeSldSym.sldParamOrSymbols.Add(New SLdParameter("Rotation", getRotation(txtSym.Angle), True))
        End If
        If placeSldSym.sldParamOrSymbols.Count = 0 Then
            Return Nothing
        End If
        Return placeSldSym
    End Function

    ''' <summary>
    ''' 设置线位置放置
    ''' </summary>
    ''' <param name="pLabelEngineLayerProps"></param>
    ''' <returns></returns>
    Private Function getSldLineLabelPlacementSymbol(pLabelEngineLayerProps As ILabelEngineLayerProperties) As SLDSymbol
        Dim placeSldSym As New SLDSymbol("LinePlacement")

        Dim p4 As IBasicOverposterLayerProperties4 = pLabelEngineLayerProps.BasicOverposterLayerProperties
        Dim offset As Double = p4.LineOffset
        If Math.Abs(offset) > 0.0001 Then
            placeSldSym.sldParamOrSymbols.Add(New SLdParameter("PerpendicularOffset", offset, True))
        End If
        If placeSldSym.sldParamOrSymbols.Count = 0 Then
            Return Nothing
        End If
        Return placeSldSym
    End Function

    ''' <summary>
    ''' 设置符号位置
    ''' </summary>
    ''' <param name="txtSymbol"></param>
    ''' <returns></returns>
    Private Function getSldDisplamentSymbol(txtSymbol As ITextSymbol) As SLDSymbol
        Dim dispsldSym As New SLDSymbol("Displacement")
        Dim pSimpleTxtSym As ISimpleTextSymbol = txtSymbol
        If Math.Abs(pSimpleTxtSym.XOffset) > 0.00001 Then
            dispsldSym.sldParamOrSymbols.Add(New SLdParameter("DisplacementX", pSimpleTxtSym.XOffset, True))
        End If
        If Math.Abs(pSimpleTxtSym.YOffset) > 0.00001 Then
            dispsldSym.sldParamOrSymbols.Add(New SLdParameter("DisplacementY", pSimpleTxtSym.YOffset, True))
        End If
        If dispsldSym.sldParamOrSymbols.Count = 0 Then
            Return Nothing
        End If
        Return dispsldSym
    End Function
    ''' <summary>
    ''' 设置定位点
    ''' Geoserver注记范围从0 0-1 1
    ''' 设置定位到来实现对齐
    ''' ________________
    ''' |               |
    ''' |               |
    ''' |               |
    ''' ----------------
    ''' </summary>
    ''' <param name="txtSymbol"></param>
    ''' <returns></returns>
    Private Function getSldAnchorSymbol(txtSymbol As ITextSymbol) As SLDSymbol
        Dim anchorSldSym As New SLDSymbol("AnchorPoint")
        Dim pSimpleTxtSym As ISimpleTextSymbol = txtSymbol
        Dim x As Double = 0
        Dim y As Double = 0
        Select Case pSimpleTxtSym.HorizontalAlignment
            Case esriTextHorizontalAlignment.esriTHACenter
                x = 0.5
            Case esriTextHorizontalAlignment.esriTHAFull
                x = 0
            Case esriTextHorizontalAlignment.esriTHALeft
                x = 0
            Case esriTextHorizontalAlignment.esriTHARight
                x = 1
        End Select
        Select Case pSimpleTxtSym.VerticalAlignment
            Case esriTextVerticalAlignment.esriTVABaseline
                y = 0
            Case esriTextVerticalAlignment.esriTVABottom
                y = 0
            Case esriTextVerticalAlignment.esriTVACenter
                y = 0.5
            Case esriTextVerticalAlignment.esriTVATop
                y = 1
        End Select
        If x <= 0.000001 And y <= 0.000001 Then
            Return Nothing
        End If
        anchorSldSym.sldParamOrSymbols.Add(New SLdParameter("AnchorPointX", x, True))
        anchorSldSym.sldParamOrSymbols.Add(New SLdParameter("AnchorPointY", y, True))
        If anchorSldSym.sldParamOrSymbols.Count = 0 Then
            Return Nothing
        End If
        Return anchorSldSym
    End Function
#End Region

#Region "设置标注权重等"
    ''' <summary>
    ''' 设置其他参数，VendorOption
    ''' </summary>
    ''' <param name="labelSldLayer"></param>
    ''' <param name="pLabelEngineLayerProps"></param>
    Private Sub setSldWeightAndSoOnVendorOption(labelSldLayer As SLDSymbolLayer,
                                       pLabelEngineLayerProps As ILabelEngineLayerProperties)
        Dim pOverPosterLayerProperties As IBasicOverposterLayerProperties4 = pLabelEngineLayerProps.BasicOverposterLayerProperties
        '<VendorOption name = "displacementMode" > NE, NW, SW, SE</VendorOption>
        'N, W, E, S, NW, NE, SW, SE.
        Dim p As IPointPlacementPriorities = pOverPosterLayerProperties.PointPlacementPriorities
        If pOverPosterLayerProperties.PointPlacementOnTop Then
            labelSldLayer.SymbolsOrParas.Add(New SLdParameter("displacementMode", "N", False, "VendorOption"))
        Else
            Dim pPriorities As String = getSldPlacePriorities(pOverPosterLayerProperties.PointPlacementPriorities)
            If Not String.IsNullOrWhiteSpace(pPriorities) Then
                labelSldLayer.SymbolsOrParas.Add(New SLdParameter("displacementMode", pPriorities, False, "VendorOption"))
            End If
        End If
        Dim pOverposterLayerProps As IOverposterLayerProperties2 = pOverPosterLayerProperties
        If Not pOverposterLayerProps.TagUnplaced Then
            labelSldLayer.SymbolsOrParas.Add(New SLdParameter("conflictResolution", "false", False, "VendorOption"))
            ' 必须设置goodnessOfFit，否则不显示
            If pOverPosterLayerProperties.FeatureType = esriBasicOverposterFeatureType.esriOverposterPolygon Then
                labelSldLayer.SymbolsOrParas.Add(New SLdParameter("goodnessOfFit", "0", False, "VendorOption"))
            End If
            labelSldLayer.SymbolsOrParas.Add(New SLdParameter("labelAllGroup", "true", False, "VendorOption"))
        Else
            If pOverPosterLayerProperties.FeatureType = esriBasicOverposterFeatureType.esriOverposterPolygon Then
                If pOverPosterLayerProperties.PlaceOnlyInsidePolygon Then
                    labelSldLayer.SymbolsOrParas.Add(New SLdParameter("goodnessOfFit", "1", False, "VendorOption"))
                Else
                    '其他情况，至少有一半在里面才显示
                End If
            End If
        End If
        If pOverPosterLayerProperties.FeatureType = esriBasicOverposterFeatureType.esriOverposterPolyline Then
            Dim pLinePosition As ILineLabelPosition = pOverPosterLayerProperties.LineLabelPosition
            If pLinePosition.ProduceCurvedLabels OrElse
                pLinePosition.Parallel Then
                labelSldLayer.SymbolsOrParas.Add(New SLdParameter("followLine", "true", False, "VendorOption"))
            End If
        End If
        '1.<VendorOption name="group">yes</VendorOption>
        '这个语句处理的是重复标注的情况。如果使用上述语句，
        '那么在预览图里将不再显示重复的标注，
        '这对处理线图层标注重复显示的问题有很重要的意义。具体的情况我们来看示例。
        '注：      VendorOption语句如果用来对标注进行限制， 一般是放在上面标记的地方，
        '      以后使用带VendorOption关键字的语句的时候， 注意位置不要放错。
        '        此外这个语句在处理面图层的标注时可能会有问题， 面标注去除重复标注的方法见7.2.3。


        '2.<VendorOption name="labelAllGroup">true</VendorOption>
        '这个语句从字面上来说，
        '        意思是显示所有的重复的标注，
        '        其实际用法也的确如此， 与上面的例子完全相反。注意lableAllGroup的赋值是true而不是yes。


        '3.<VendorOption name="spaceAround">10</VendorOption>
        '这个语句用来控制两个标注之间的距离， 如果两个标注在设置的距离内，
        '        那么只会显示一个标注（而不是默认的知道两个标注即将重叠才隐藏）。
        '这里将spaceAround赋值为10， 单位是像素， 那么每个标注距离其他标注至少有20个像素的距离。
        '之前给出的例子过于简单， 这里依然选取一个复杂的例子来讲解。
        '图层准备：   gismm : POI（此图层是茂名市各个地点的矢量图， 数据量很大）。
        'Style准备： mmpnt2（原图层设置了比例尺分级显示， 这里我将其简化， 去掉所有过滤条件直接显示）。
        '        设置两个标注之间的距离在配图的时候经常用到， 这是一个很常用的功能。
        '        Geoserver一般默认VendorOption的取值为0， 我们可以手动设置来调整标注的显示。
        '注：      VendorOption的值可以取负数， 这样会造成标注重叠的情况。如果不是特别重要的标注， 不建议这么做。


        '4.<VendorOption name="followLine">true</VendorOption>
        '在前面“线标注的特性设置”这一小节里， 我们提到了将线标注设置成和线平行的方法。
        '        在所设置的线是直线的情况下， 这种设置没什么问题。但是很多时候我们会遇到曲线的情况。
        '        将标注设置成与曲线平行的时候， 系统会取曲线的中点， 在该点显示一个与该点切线平行的标注。
        '        使用本语句可以强制规定标注始终跟随线的走向， 不会出现脱离线的情况。

        '5.<VendorOption name="maxDisplacement">10</VendorOption>
        '这个语句也是用来处理点、线、面标注出现重叠的情况。一般来说，
        'geoserver遇到标注重叠时会默认有的标注不显示， 来规避重叠。
        '        我们在前面也了解到可以强制将VendorOption设置成负数来避免重要的标注被隐藏。
        '本语句提供了一个折中的方法： 当出现标注会被隐藏的情况的时候，
        '        标注会在设置的值的范围内自动寻找合适的位置来显示。比如两条线的距离过近， 
        '        彼此平行， 长度相同， 设置其标注在中点沿线显示，
        '        可能就会出现标注的重叠。使用上面语句之后，
        '         将被隐藏的标注将会寻找线上10个像素范围内的其他位置来进行显示。
        '这个功能在点、线、面的标注显示上都可以应用。

        '6.<VendorOption name="repeat">100</VendorOption>
        '此语句主要用来设置过长的线的标注显示问题。我们在给地图配置标注的时候
        '            ，为了提升地图加载的速度，一般将road类图层每条线打断成很多的对象，
        '因此一般不会出现过长的线标注只有一个这种情况。有时遇到了非常长的线只有一个标注，
        '想要增加它的标注， 就需要使用这个语句。Repeat， 即重绘， 可以将标注反复显示。
        '        后面的值设置的是标注之间的距离， 可以理解为重绘的参数。将值设置为100， 
        '        那么标注将会隔100个像素显示1次。
        '注：      将5、6的语句一起使用的时候，maxDisplacement的值必须要小于repeat的值，
        '否则标注无法显示。

        '7.<VendorOption name="maxAngleDelta">15</VendorOption>
        '本语句用来控制线标注的最大角度。我们知道，线标注一般显示在线的中间，
        '如果一条线刚好在中间弯曲， 而我们设置了标注始终在线上的话，
        '        标注的文字就会不在一条直线上。如果弯曲程度过大， 
        '        看起来字就会不够美观。这里控制的就是标注文字显示的最大角度， 
        '不建议其值超过30。我们可以将本语句与MaxDisplacement配合使用， 将标注尽量显示在一条直线上。

        '8.<VendorOption name="autoWrap">50</VendorOption>
        '这里控制的是标注的换行问题， 一般用在面图层的标注显示上面。我们假设这样一个场景， 
        '        “中华人民共和国”七个字在世界地图上的小比例尺上勉强可以一排显示，
        '        “大不列颠及北爱尔兰联合王国”要一排显示完就有点困难了。在之前的配图中，
        ' 一旦一个区域过窄， 无法容纳标注在相应的范围内显示完（超出一小部分没问题），
        '        其标注会被隐藏。设置标注换行后， 标注就不再被隐藏了。在上面的语句中，
        '         我设置的值为50， 那么允许一行显示标注的最大宽度为50个像素， 超过50个像素宽度的标注将会换行。

        '9.<VendorOption name="forceLeftToRight">true</VendorOption>
        '前面设置线标注的时候， 标注与线平行。大多数情况下， 这种设置美观而且便于识别标注的归属。
        '        但是我们知道， 0°和180°的线也是平行的， 这就意味着有的标注可能和我们理想的完全相反，
        '        一条水平的线其标注可能倒着来显示。我们使用这个语句可以强制设定标注一定是由左向右读的，
        '         使其显示符合我们的习惯。

        '10.<VendorOption name="conflictResolution">false</VendorOption>
        '前面很多地方说到了标注的重叠问题， 本语句对标注重叠的情况进行设置。
        '        如果将spaceAround设置为负数的话， 标注是可以重叠的，
        '        但是其取值决定了容忍重叠的范围。使用本语句不需要设置范围， 
        '        其值为false的时候， 所有的标注均可重叠。

        '11.<VendorOption name="goodnessOfFit">0.3</VendorOption>
        '这个语句是用来过滤掉一些特别不适合有标注的地方， 系统默认其取值为0.5
        ' 对面有效，
        '如果设置为1：则表示标注基本完全在面内才显示，0表示全部显示，0.5表示一半在里面

        '12.<VendorOption name="polygonAlign">mbr</VendorOption>
        If pOverPosterLayerProperties.FeatureType = esriBasicOverposterFeatureType.esriOverposterPolygon Then
            Select Case pOverPosterLayerProperties.PolygonPlacementMethod
                Case esriOverposterPolygonPlacementMethod.esriAlwaysHorizontal

                Case esriOverposterPolygonPlacementMethod.esriAlwaysStraight
                    labelSldLayer.SymbolsOrParas.Add(New SLdParameter("polygonAlign", "ortho", False, "VendorOption"))

                Case esriOverposterPolygonPlacementMethod.esriMixedStrategy
                    labelSldLayer.SymbolsOrParas.Add(New SLdParameter("polygonAlign", "mbr", False, "VendorOption"))

            End Select
        End If
        '前面提到过区域里的标注显示问题。如果区域水平方向过窄，标注将无法显示，会被隐藏。
        '使用这个语句可以将标注旋转， 自动调整至可以显示的方向。

        '13.<VendorOption name="graphic-resize">stretch</VendorOption>
        '这句代码是针对显示在图片里的标注的设置， 前面讲到线标注配置的时候，
        '        有的标注并不单纯是文字， 其外面有一个有颜色填充的边框。边框默认大小一致， 
        '        因此有的字比较多会超出， 有的字比较少比较空旷。
        '        使用这句代码可以根据字段的长短将边框调整至自适应的大小。
        '注：      只有对引用图片使用默认大小的可以使用本语句， 如果你加了size对外部图片的大小进行了限制，
        '        那么可能会出现标注不显示等问题。在提供的简单图层上面尝试本语句标注没有显示， 原因不明。
        '        其用法有待发掘。
        labelSldLayer.SymbolsOrParas.Add(New SLdParameter("graphic-resize", "stretch", False, "VendorOption"))
        '14.<VendorOption name="partials">true</VendorOption>
        '本代码是用来处理在边界的点的情况（点出现这种情况比较多）。
        '在一幅地图的边界部分， 其标注如果长度超出了地图范围， 将会被隐藏。
        '        使用本语句之后， 标注将会在邻近合适的地方进行显示。
        '注：      VendorOption关键字很多， 这里只是选取了部分， 而且它不只是用来对标注进行控制，
        '        其用法的灵活多变给我们的学习造成了很多困难。如果日后了解了它其他的用法， 欢迎对本部分进行补充。

    End Sub
    ''' <summary>
    ''' 设置点放置优先级
    ''' </summary>
    ''' <param name="p"></param>
    ''' <returns></returns>
    Private Function getSldPlacePriorities(p As IPointPlacementPriorities) As String
        If p Is Nothing Then
            Return ""
        End If
        Dim pList As New Dictionary(Of Integer, List(Of String))
        'N
        addWeightToList(pList, p.AboveCenter, "N")
        'W
        addWeightToList(pList, p.CenterLeft, "W")
        'E
        addWeightToList(pList, p.CenterRight, "E")
        'S
        addWeightToList(pList, p.BelowCenter, "S")
        'NW
        addWeightToList(pList, p.AboveLeft, "NW")
        'NE
        addWeightToList(pList, p.AboveRight, "NE")
        'SW
        addWeightToList(pList, p.BelowLeft, "SW")
        'SE
        addWeightToList(pList, p.BelowRight, "SW")
        Dim keys As List(Of Integer) = pList.Keys.ToList()
        keys.Sort()
        Dim lstDirections As New List(Of String)
        For Each key In keys
            Dim vs As List(Of String) = pList.Item(key)
            For Each v In vs
                lstDirections.Add(v)
            Next
        Next
        If keys.Count = 1 AndAlso lstDirections.Count = 8 Then
            Return ""
        End If
        Return String.Join(",", lstDirections)
    End Function
    ''' <summary>
    ''' 获取权重
    ''' </summary>
    ''' <param name="pList"></param>
    ''' <param name="weight"></param>
    ''' <param name="mode"></param>
    Private Sub addWeightToList(pList As Dictionary(Of Integer, List(Of String)),
                                         weight As Integer, mode As String)
        If weight <= 0 Then
            Return
        End If
        If Not pList.ContainsKey(weight) Then
            pList.Add(weight, New List(Of String))
        End If
        pList.Item(weight).Add(mode)
    End Sub
#End Region

    ''' <summary>
    ''' 设置注记只在地图中显示，mapOnly:只显示；......
    ''' </summary>
    ''' <param name="rule"></param>
    Private Sub setSldGenralVendorOption(rule As SLDRule)
        '<VendorOption name="inclusion">mapOnly</VendorOption>
        rule.add(New SLdParameter("inclusion", "mapOnly", False, "VendorOption"))
    End Sub


End Class
